package com.xmcc.service.impl;


import com.google.common.collect.Lists;
import com.xmcc.dao.SysDeptMapper;
import com.xmcc.dto.SysDeptTreeDto;
import com.xmcc.pojo.SysDept;
import com.xmcc.service.SysTreeService;
import com.xmcc.utill.LevelUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;

@Service
public class SysTreeServiceImpl implements SysTreeService {

    @Autowired
    private SysDeptMapper sysDeptMapper;
    @Override
    public List<SysDeptTreeDto> sysDeptTree() {
        List<SysDept> sysDepts = sysDeptMapper.queryAllSysDept();
        //把List<SysDept>转换为 List<SysDeptTreeDto>：
        // 创建一个List放SysDeptTreeDto对象：
        List<SysDeptTreeDto> treeDtoList = Lists.newArrayList();
        SysDeptTreeDto sysDeptTreeDto;
        for (SysDept sysDept : sysDepts) {
            //调用工具类，完成每个SysDept对象的属性赋值到SysDeptTreeDto对象：
            sysDeptTreeDto = SysDeptTreeDto.getSysDeptTreeDto(sysDept);
            //然后把每个SysDeptTreeDto对象又存进List集合中：
            treeDtoList.add(sysDeptTreeDto);
        }
        //返回一个根部门的list集合，有层次的树形集合：（里面包含子部门）
        //直接把查出的所有信息的list集合交给一个方法完成：
        return getDeptTree(treeDtoList);
    }

    private List<SysDeptTreeDto> getDeptTree(List<SysDeptTreeDto> treeDtoList) {
        //假如传过来的数组等于null或者长度小于0，就返回null
        if(CollectionUtils.isEmpty(treeDtoList)){
            return null;
        }
        //第一级
        List<SysDeptTreeDto> rootList = Lists.newArrayList();
        //key 是level  value是当前level对应的所有部门
        Map<String,List<SysDeptTreeDto>> levelMap = new HashMap<>();
        //谷歌
        //Multimap<String,SysDeptTreeDto> multimap = ArrayListMultimap.create();
        //把所有的根部门保存起来：
        for (SysDeptTreeDto sysDeptTreeDto : treeDtoList) {
            //取出每一个部门的level：
            String level = sysDeptTreeDto.getLevel();
            //判断是否是0级部门：根部门
            if(LevelUtil.ROOT_LEVEL.equals(level)){
                rootList.add(sysDeptTreeDto);
            }else{
                //不是0级部门的，都用map保存起来：key对应level字段，value对应list集合：
                //1种情况是已经有了 就只需要把当前对象加入集合  2、如果没有 就put
                List<SysDeptTreeDto> levelList = levelMap.get(level);
                if(CollectionUtils.isEmpty(levelList)){//当前level为key的 还没有放过的对象
                    levelList = new ArrayList<>();
                    levelMap.put(level,levelList);//表示还没有放过这个key
                }
                /* Map中的key对应每个部门的level，value对应list集合，
                   所有把map中的key就是相同的level，用list结合放入该level对应的部门对象：   */
                levelList.add(sysDeptTreeDto);
            }
        }
        //排序  因为现在是引用对象  java不知道你要按什么排 所以需要自定义一个比较器：
        //java中定义比较器 实现该Compartor接口，都是比较器：
        //  把根部门就是0级部门排序：第一个参数就是，你要排序的list集合，第二个参数是一个比较器：
        Collections.sort(rootList, deptComparator);
        //填充树：目的：把每个子部门属于哪里父部门递归生成树起来：直接调用一个方法，让该方法来递归实现：
        //把需要填充树的两个集合或者map传入进去：
        fillDeptTree(rootList,levelMap);
        return rootList;
    }
    //递归生成树：
    private void fillDeptTree(List<SysDeptTreeDto> rootList, Map<String,List<SysDeptTreeDto>> levelMap) {
        for(int i=0;i<rootList.size();i++){
            //获得每个SysDeptTreeDto对象：
            SysDeptTreeDto sysDeptTreeDto = rootList.get(i);
            //获得该对象的下一层的level：
            String level = LevelUtil.getLevel(sysDeptTreeDto.getLevel(),sysDeptTreeDto.getId());
            /* 如果map集合中有对应得该key就把该value值的list集合设置在该父部门SysDeptTreeDto对象中list属性中，
                 该list集合然后对象继续递归：*/
            List<SysDeptTreeDto> childList = levelMap.get(level);
            if(!CollectionUtils.isEmpty(childList)){//表示子部门列表不为空，为空就不进入这里了
                //排序
                Collections.sort(rootList, deptComparator);
                //把map中有该层的level的value值list集合设置在SysDeptTreeDto对象中list属性：
                sysDeptTreeDto.setList(childList);
                //如果子部门还有部门就继续递归：
                fillDeptTree(childList,levelMap);
            }
        }
    }
    //比较器
    Comparator deptComparator=new Comparator<SysDeptTreeDto>() {
        @Override//返回的是负数 就表示o1 小于o2  如果返回的是0 就表示两个相等 如果是正数。。。
        public int compare(SysDeptTreeDto o1, SysDeptTreeDto o2) {
            //规定选择的seq值越大 优先级越高
            return  o1.getSeq()-o2.getSeq();
        }
    };
}
